#include "stdafx.h"
#include "bmp.h"

#define DS_BITMAP_FILEMARKER  ((WORD) ('M' << 8) | 'B')    // is always "BM" = 0x4D42

CBmp::CBmp( )
{
	m_pBitmap = NULL;
	ZeroMemory( &m_BMI, sizeof(BITMAPINFO));
}

CBmp::~CBmp( )
{
	if( m_pBitmap )
		delete[] m_pBitmap;
}

int	CBmp::GetWidth()
{
	return m_BMI.bmiHeader.biWidth;
}

int	CBmp::GetHeight()
{
	return m_BMI.bmiHeader.biHeight;
}

BOOL CBmp::Load( char * lpszFileName )
{
	BITMAPFILEHEADER bfh;
	FILE *fp;
	fopen_s(&(fp), lpszFileName, ("rb") );
	if( !fp )
		return FALSE;

	if( 1!=fread( &bfh, sizeof(BITMAPFILEHEADER), 1, fp ) )
	{
		TRACE( "can't read bitmap file header from %s\n", lpszFileName );
		fclose( fp );
		return FALSE;
	}

	// Check that we have the magic 'BM' at the start.
	if (bfh.bfType != DS_BITMAP_FILEMARKER)
	{
		TRACE( "not a bitmap file %s\n", lpszFileName );
		fclose( fp );
		return FALSE;
	}

	if( 1!=fread( &m_BMI, sizeof(BITMAPINFOHEADER), 1, fp ) )
	{
		TRACE( "can't read bitmap header from %s\n", lpszFileName );
		fclose( fp );
		return FALSE;
	}

	// Check that we have a real Windows DIB file.
	if (m_BMI.bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
	{
		TRACE("file is not a Windows DIB %s\n", lpszFileName );
		fclose( fp );
		return FALSE;
	}

	if( m_BMI.bmiHeader.biBitCount!=24 )
	{
		TRACE("not 24 bit bitmap %s\n", lpszFileName );
		fclose( fp );
		return FALSE;
	}

	if( 0!=fseek( fp, bfh.bfOffBits, SEEK_SET ) )
	{
		TRACE("can't seek to bitmap data %d, %s\n", bfh.bfOffBits, lpszFileName);
		fclose( fp );
		return FALSE;
	}

	// So how big the bitmap surface is.
	int size = bfh.bfSize - bfh.bfOffBits;

	// Allocate the memory for the bits and read the bits from the file.
	m_pBitmap = new BYTE[size];

	if (!m_pBitmap) 
	{
		TRACE("Out of memory for DIB bits %d bytes, %s\n", size, lpszFileName);
		fclose( fp );
		return FALSE;
	}

	if( 1!=fread( m_pBitmap, size, 1, fp ) )
	{
		TRACE("can't read bitmap data %d bytes, %s\n", size, lpszFileName);
		delete[] m_pBitmap;
		m_pBitmap = NULL;
		fclose( fp );
		return FALSE;
	}

	fclose( fp );

	return TRUE;

}

BOOL	CBmp::Draw( HDC hDC, CRect & rcDst, CRect & rcSrc )
{
	if( hDC == NULL ) return FALSE;
	if( m_pBitmap == NULL ) return FALSE;
	return GDI_ERROR!=StretchDIBits(
		hDC,
		rcDst.left,
		rcDst.top,
		rcDst.Width(),
		rcDst.Height(),
		rcSrc.left,
		rcSrc.top,
		rcSrc.Width(),
		rcSrc.Height(),
		m_pBitmap,
		&m_BMI,
		DIB_RGB_COLORS,
		SRCCOPY );
}

BOOL	CBmp::Draw( HDC hDC, CPoint ptDest )
{
	if( hDC == NULL ) return FALSE;
	if( m_pBitmap == NULL ) return FALSE;

	int width = m_BMI.bmiHeader.biWidth;
	int height = m_BMI.bmiHeader.biHeight;

	return GDI_ERROR!=StretchDIBits(
		hDC,
		ptDest.x,
		ptDest.y,
		width,
		height,
		0,
		0,
		width,
		height,
		m_pBitmap,
		&m_BMI,
		DIB_RGB_COLORS,
		SRCCOPY );
}
BOOL CBmp::Draw( CDC* pDC, CRect& rcDst, CRect& rcSrc )
{
	return Draw( pDC->GetSafeHdc(), rcDst, rcSrc );
}

BOOL CBmp::Draw( CDC* pDC, CPoint ptDest )
{
	return Draw( pDC->GetSafeHdc(), ptDest );
}

BOOL	CBmp::DrawBitmap( CDC* pDC, CRect & rcDst, CRect & rcSrc )
{
	return DrawBitmap( pDC->GetSafeHdc(), rcDst, rcSrc );
}

BOOL	CBmp::DrawBitmap( CDC* pDC, CPoint ptDest )
{
	return DrawBitmap( pDC->GetSafeHdc(), ptDest );
}

BOOL	CBmp::DrawBitmap( HDC hDC, CRect & rcDst, CRect & rcSrc )
{
	if( hDC == NULL ) return FALSE;
	if( GetSafeHandle() == NULL ) return FALSE;
	BITMAP BitMap;
	this->GetBitmap(& BitMap);
	HDC hdcImage;
	hdcImage = CreateCompatibleDC( NULL ); 
    SelectObject( hdcImage, this->GetSafeHandle() ); 
	BOOL bRet =  ::StretchBlt( 
		hDC,
		rcDst.left,
		rcDst.top,
		rcDst.Width(),
		rcDst.Height(),
		hdcImage,
		rcSrc.left,
		rcSrc.top,
		rcSrc.Width(),
		rcSrc.Height(),
		SRCCOPY);
	::DeleteDC( hdcImage );
	return bRet;
}

BOOL	CBmp::DrawBitmap( HDC hDC, CPoint ptDest )
{
	if( hDC == NULL ) return FALSE;
	if( GetSafeHandle() == NULL ) return FALSE;
	BITMAP BitMap;
	this->GetBitmap(& BitMap);
	int width =  BitMap.bmWidth;
	int height = BitMap.bmHeight;
	HDC hdcImage;
	hdcImage = CreateCompatibleDC( NULL ); 
    SelectObject( hdcImage, this->GetSafeHandle() ); 

	BOOL bRet = ::StretchBlt( 
		hDC,
		ptDest.x,
		ptDest.y,
		width,
		height,
		hdcImage,
		0,
		0,
		width,
		height,
		SRCCOPY);
	::DeleteDC( hdcImage );
	return bRet;
}